实现简单的ASP MVC框架
ASP曾经非常流行,我上大学那会儿,图书馆书架上写Web编程的书籍里面讲ASP的占了大多数,给我一个错觉,ASP就是最牛逼的编程语言。事实上ASP连编程语言都不算,ASP只是提供了几个对象的接口给脚本语言进行编程。ASP默认支持的脚本语言是VBScript,但从2006年开始流行WEB 2.0的概念后,JavaScript成了最热门的编程语言之一。也就是从那时开始,不断有人采用JavaScript作为ASP的编程语言。JavaScript的语法比较灵活,特别是高阶函数、闭包等特性,比VBScript中规中矩的编程风格好用太多了。但比较遗憾的是,JavaScript默认的类型当中没有用于处理二进制数据的类型,处理二进制类型数据的时候,需要使用一定的技巧。ASP虽然已经流行过那么多年,但是一直没有出现一套比较好用的Web开发框架,多数应用都是停留在一个请求对应一个页面的处理方式。我设计了一个简单的MVC框架,用于应对一些简单快捷的开发需求,同时对这个问题提供一点解决思路,算是对ASP知识的一点总结。
1 运行环境
打开IIS Express的调试ASP的相关选项,用IIS Express来运行调试ASP是比较方便的,功能与相应版本的IIS是类似的,只是少了管理界面,特别对于还在跑Win 2003的主机,IIS Express可以让PHP、JSP等多种技术同时共享80端口提供服务。 打开IIS Express的配置文件C:\Documents and Settings\$YourName$\My Documents\IISExpress\config\applicationHost.config 找到节点 <system.webServer>下的<asp>节点修改为如下代码:
<asp |
2 目录结构
想要实现rest风格的URL,需要通过rewrite规则来实现,可以实现单文件入口,完全割掉.asp这个尾巴。框架的目录结构:
目录 | 文件 | 备注 | |
├── | controller | 控制器 | |
│ | ├── | index.asp | |
│ | └── | user.asp | |
├── | model | 模型 | |
│ | ├── | article.asp | |
│ | └── | user.asp | |
├── | view | 视图 | |
│ | ├── | index.asp | |
├── | index.asp | 框架入口 | |
└── | web.config | 配置信息 |
通过配置rewrite规则,除去URL中有对应的目录和文件,其他请求都转发到框架入口文件index.asp中。一次请求过程如下:首先检查url是否复合reset风格,读取相应的Controller和Action方法,读取过的Controller就会缓存到Application中,接着根据Action方法参数名,注入相应的请求参数,Action方法进行必要的数据验证之后,调用对应Model的方法取得数据,读取过的Model方法同样会缓存起来,最后把数据填充到对应的View中,同样View的预编译结果也会缓存起来。之后的请求就直接从内存中读取对应的脚本,不需要再通过adobe.stream组件读取脚本文件,请求的响应就会更加快。
<?xml version="1.0" encoding="UTF-8"?> |
3 缓存
为了较少磁盘读写的次数,我将所有需要读入的文件都缓存到Application对象当中,比如模板、控制器、模型等。框架当中有三个函数用到了cache缓存函数,需要缓存的内容都通过cache回调函数来实现的。巧妙的地方在于cache函数的第二个参数是回调函数,把回调函数返回的内容进行缓存。比如readAllText函数是调用cache函数得到的返回值,cache函数的第一个参数是函数名+相对路径(为了区分不同函数读取同一个文件的情况),第二个参数传入一个封装了读写步骤的匿名函数。还有类似的缓存例子,就是模板引擎的实现,模板引擎先将模板读取进来,然后预编译成函数体,接着编译成函数,最后根据填充数据生成输入内容。因为Application对象只能缓存字符串,无法缓存函数对象,为了进一步减少运算成本,把函数体缓存到Application对象当中。
function readAllText(path,encoding){ |
4 包管理问题
引入类似Node.js包管理机制,只是一个简单的实现,通过函数导入模块而不是包含语句,可以简化代码结构,而所有的读文件的操作,都进行了缓存。这里涉及到3个函数
//导入模块 |
5 模版引擎
说得好听叫模版引擎,其实就是一个函数,函数的原型来源于JQuery的作者John Resig的Micro-Templating,针对ASP的运行环境进行了一些调整。支持子模板,用<%=变量名%>形式输出填充数据。
//模板编译函数 |
6 数据库操作
JavaScript比较强大的地方就在于可以将函数作为参数传递给另外一个函数。这一特性对于抽取共性的操作封装成函数或者库来说,就像是一把屠龙刀。下面就让我们见识一些它的威力。
//数据库查询函数 |
一些简单的数据库操作可以直接调用query函数,把SQL执行生成的表格数据转化为JavaScript对象数组,以便于将数据传递到视图。一些更复杂的情景下,比如调用存储过程,你需要设置参数名称,参数类型和参数长度才能正确调用,这时候你可以传入一个回调函数,用于生成数据模型对象,用于填充试图。
7 上传问题
JavaScript自带的函数库当中并没有用于处理二进制数据的方法,网络上的各路大神,想尽了各种方法,试图为JavaScript增加这个能力。有人通过MSScriptControl.ScriptControl控件,调用VBScript的函数来实现,有人通过Adodb.Steam对象,把二进制数据转换成unicode字符来处理,还有人将VBScript的上传类封装成sct组件。封装成sct组件的方式在代码执行效率和代码组织都是比较有优势的。曾经我也比较喜欢这样的解决方案,直到我见到第四种解决思路,我才豁然开朗。原来Microsoft.XMLDOM组件是具有处理二进制数据的能力的,通过指定节点的dataType为bin.hex,你就可以直接给节点的noteTypeValue赋值二进制数据,节点的text属性就是二进制数据对应的16进制字符串。对二进制的数据的分析就可以转换到对16进制字符串的分析。
function Upload(){ |